package net.oov.identify.model;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;

import net.oov.identify.SequenceFreqContainer;
import net.oov.identify.StatusTree;
import net.oov.identify.StatusTree.TreeNode;
import net.oov.identify.support.Distribution;
import net.oov.identify.util.CallBack;

public class CheckExtModel implements CheckModel{
	
	private List<CheckModel> modelList = new ArrayList<CheckModel>() ;
	private LengthModel lm = null;
	private FreqModel fm = null;
	private ConfModel cm = null;
	private MutualInfoModel mi = null;
	private NGramModel ng = null;
	private TTestModel tt = null;
	private MutualInfoExtModel mix = null;
	
	private Double minMiValid = 100d;
	private Double minConfValid = 100d;
	private Double minNgramValid = 100d;
	private Integer minFreqValid = 100;
	private Integer minWFreqValid = 100;
	private Integer sumOfValidFreq = 0;
	
	OutputStreamWriter bw = null;
	
	
	public Boolean decision(StatusNode ct,CharSequence cs){
		
		if(fm!=null){
			if(!fm.check(ct,cs))return Boolean.FALSE;
		}
		if(lm!=null){
			if(!lm.check(ct,cs))return Boolean.FALSE;
		}
		if(mi!=null){
			if(!mi.check(ct,cs))return Boolean.FALSE;
		}
		if(ng!=null){
			if(!ng.check(ct,cs))return Boolean.FALSE;
		}
		if(cm!=null){
			if(!cm.check(ct,cs))return Boolean.FALSE;
		}
		if(mix!=null){
			if(!mix.check(ct,cs))return Boolean.FALSE;
		}
		if(tt!=null){
			if(!tt.check(ct,cs))return Boolean.FALSE;
		}

		return Boolean.TRUE;
	}
	
/*	*//**
	 * 对词的左右两边互信息值进行评估
	 * @param minMi 有效互信息值
	 * @param dValue 左右两边差值边界
	 * @return
	 *//*
	public Boolean checkLRMi(Double minMi,Double dValue){
		//如果频率接近，加大检查力度，即d1减小，或者d2加大
		return Boolean.TRUE;
	}
	
	public Boolean freqDecision(){
		return false;
	}
	
	public Boolean mutualInfoDecision(){
		return false;
	}
	
	public Boolean confDecision(){
		return false;
	}
	
	
	public Double mutualInfo(){
		Double mi = null;
		return mi;
	}
	
	public Double conf(){
		Double conf = null;
		return conf;
	}*/

	public void addModel(CheckModel cd){
		if(cd instanceof LengthModel){
			lm = (LengthModel)cd;
		}else if(cd instanceof MutualInfoModel){
			mi = (MutualInfoModel)cd;
		}else if(cd instanceof  FreqModel){
			fm  = (FreqModel)cd;
		}else if(cd instanceof  ConfModel){
			cm  = (ConfModel)cd;
		}else if(cd instanceof  NGramModel){
			ng  = (NGramModel)cd;
		}else if(cd instanceof  TTestModel){
			tt  = (TTestModel)cd;
		}else if(cd instanceof MutualInfoExtModel){
			mix = (MutualInfoExtModel)cd;
		}else{
			throw new RuntimeException("没有对应模型");
		}
		this.modelList.add(cd);
	}
	
	public String info(){
		StringBuilder ret = new StringBuilder();
		if(fm!=null){
			ret.append(" F:");
			ret.append(fm.value());
			ret.append("\t");
		}
		if(cm!=null){
			ret.append(" C:");
			ret.append(Math.round(cm.value()*100000)/100000d);
			ret.append("\t");
		}
		if(ng!=null){
			ret.append(" N:");
			ret.append(Math.round(ng.value()*100000)/100000d);
			ret.append("\t");
		}
		if(mi!=null){
			ret.append(" M:");
			ret.append(Math.round(mi.value()*100000)/100000d);
			ret.append("\t");
		}
		if(mix!=null){
			ret.append("->ML:");
			ret.append(mix.miValueL);
			ret.append(" MR:");
			ret.append(mix.miValueR);
		}
		if(tt!=null){
			ret.append(" T:");
			ret.append(tt.value());
		}
		return ret.toString();
	}
	
	
	@Override
	public Double conf(StatusNode ct, CharSequence cs) {
		if(cm == null)return null;
		return cm.value(ct, cs);
	}

	@Override
	public Double mi(StatusNode ct, CharSequence cs) {
		if(mi==null)return null;
		return mi.value(ct, cs);
	}

	@Override
	public Double ngram(StatusNode ct, CharSequence cs) {
		if(ng == null)return null;
		return ng.value(ct, cs);
	}

	public Double value(StatusNode ct, CharSequence cs){
		return null;
	}
	
	public Boolean check(StatusNode ct, CharSequence cs) {
		return decision(ct, cs);
	}

	public static void wl(Object s){
		System.out.println(s);
	}
	
	/**
	 * @param cm
	 * @param file
	 */
	public void out2File(SequenceFreqContainer container,String file){
		
		FileOutputStream fo = null;

			try {
				fo = new FileOutputStream(new File(file));
				bw = new OutputStreamWriter(fo,"UTF-8");
			} catch (FileNotFoundException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			} catch (UnsupportedEncodingException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}

		
		String str = "";
		
		for(Entry<Character,StatusTree> en:container.getDicForward().entrySet()){
			this.dd(str, en.getValue().rootNode());
		}
		
		StringBuilder sb = new StringBuilder();
		sb.append("\n");
		sb.append("minFreqValid:");
		sb.append(minFreqValid);
		sb.append(" ");
		sb.append("minConfValid:");
		sb.append(minConfValid);
		sb.append(" ");
		sb.append("minMiValid:");
		sb.append(minMiValid);
		sb.append(" ");
		sb.append("minNgramValid:");
		sb.append(minNgramValid);
		sb.append(" ");
		sb.append("minWFreqValid:");
		sb.append(minWFreqValid);
		sb.append(" ");
		
		sb.append("\n");
		sb.append("sumOfValidFreq:");
		sb.append(sumOfValidFreq);
		
		try {
			bw.write(sb.toString());
			bw.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	public Distribution getDistributionInfo(SequenceFreqContainer container){
		
		//分布模型
		final Distribution di = new Distribution(5, 0, "大于频次", "数量");
		
		StringBuilder sb = new StringBuilder();
		String str = "";
		for(Entry<Character,StatusTree> en:container.getDicForward().entrySet()){
			final TreeNode treeNode = en.getValue().rootNode();
			this.dd(str, treeNode, new CallBack(){public void execute(){di.add(treeNode.freqWhole().doubleValue(), 1);}});
		}
		
		sb.append("\n");
		sb.append("sumOfValidFreq:");
		sb.append(sumOfValidFreq);
		
		try {
			di.out2Excel("e:\\原生汉字串频次分布.xls", "原生汉字串频次分布");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		return di;
	}
	
	private void dd(String str,TreeNode treeNode){
		dd(str, treeNode, null);
	}
	
	private void dd(String str,TreeNode treeNode, CallBack callBackForDistribution){
		
		str = str+treeNode.getKey();
		if(treeNode.isEndpoint()){
			boolean isCheckValid = this.check(treeNode, str);
			if(isCheckValid){
				
				if(this.mi(treeNode, str)!=null && minMiValid>this.mi(treeNode, str))minMiValid = this.mi(treeNode, str);
				if(this.conf(treeNode, str)!=null && minConfValid>this.conf(treeNode, str))minConfValid = this.conf(treeNode, str);
				if(this.ngram(treeNode, str)!=null && minNgramValid>this.ngram(treeNode, str))minNgramValid = this.ngram(treeNode, str);
				if(minFreqValid>treeNode.freq())minFreqValid = treeNode.freq();
				if(minWFreqValid>treeNode.freqWhole())minWFreqValid = treeNode.freqWhole();
				
				if(callBackForDistribution!=null){
					callBackForDistribution.execute();
				}
				
				sumOfValidFreq += treeNode.freq();
				
				try {
					bw.write(str+"\t"+this.info()+" "+treeNode.toString()+"\n");
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			}
		}
		if(!treeNode.isLeaf()){
			for(Entry<Character,TreeNode> en:treeNode.subNodes().entrySet()){
				dd(str, en.getValue(), callBackForDistribution);
			}
		}
	}
	
}
